import { Logger } from '@/components/useLogger';

import {
  devAuth,
  digestData,
  enumCertContainer,
  enumDevice,
  exportPubKey,
  generateRandom,
  loadLibrary,
  login,
  loginSoPin,
  makeRequest,
  setDigestMethod,
  setUserID,
  signData,
} from './usbKeyMethod';

// 将 Uint8Array 类型的输入数据进行 Base64 编码
function base64Encode(input: Uint8Array): string {
  let binary = ''; // 初始化一个空字符串，用于存储转换后的二进制数据
  const len = input.byteLength; // 获取输入数据的长度

  // 遍历输入数据中的每一个字节
  for (let i = 0; i < len; i++) {
    // 将每个字节转换为对应的字符，并拼接到二进制字符串上
    binary += String.fromCharCode(input[i]);
  }

  // 使用 window.btoa() 方法将二进制字符串进行 Base64 编码，并返回结果
  return window.btoa(binary);
}

// 将 Base64 编码的字符串解码为 Uint8Array 类型的数据
function base64Decode(input: string): Uint8Array {
  // 使用 window.atob() 方法将输入的 Base64 编码字符串解码为原始的二进制字符串
  const binary = window.atob(input);
  const len = binary.length; // 获取解码后的二进制字符串的长度
  const bytes = new Uint8Array(len); // 创建一个与长度相同的 Uint8Array 类型的数组，用于存储解码后的字节数据

  // 遍历解码后的二进制字符串中的每一个字符
  for (let i = 0; i < len; i++) {
    // 获取每个字符的 Unicode 编码，并存储到字节数组中对应的位置
    bytes[i] = binary.charCodeAt(i);
  }

  // 返回存储解码后字节数据的字节数组
  return bytes;
}

// 用户登录函数
export async function loginUser(
  roleName: string,
  authPassWd: string,
  soPin: string,
  userPin: string,
  userId: string,
  random: string,
): Promise<{
  signature: string;
  digest: string;
  originData: string;
}> {
  try {
    const loadLibraryResult = await loadLibrary(
      'mtoken_gm3000.dll',
      'libgm3000.1.0.so',
      'libgm3000.1.0.dylib',
    );
    if (loadLibraryResult.rtn !== 0) {
      throw new Error(`加载库失败，错误码: ${loadLibraryResult.errorCode}`);
    }

    // 查找设备
    const devices = await enumDevice();
    if (devices.rtn !== 0 || !devices.array || devices.array.length === 0) {
      throw new Error('未找到任何设备');
    }

    // 处理以 "||" 分隔的设备名字符串
    const deviceNames = devices.array.split('||');
    const deviceName = deviceNames[0]; // 假设我们使用第一个设备

    // USBKey初始化
    const initializeResult = await makeRequest({
      function: 'SOF_Initialize',
      deviceName,
    });
    if (initializeResult.rtn !== 0) {
      throw new Error(`初始化失败，错误码: ${initializeResult.errorCode}`);
    }

    // 认证设备
    const devAuthResult = await devAuth(deviceName, authPassWd);
    if (devAuthResult.rtn !== 0) {
      throw new Error(`设备认证失败，错误码: ${devAuthResult.errorCode}`);
    }

    // 验证应用管理密码 soPin
    const loginSoPinResult = await loginSoPin(deviceName, soPin);
    if (loginSoPinResult.rtn !== 0) {
      throw new Error(`应用管理 PIN 验证失败，错误码: ${loginSoPinResult.errorCode}`);
    }

    // 用户PIN登录
    const loginUserResult = await login(deviceName, userPin);
    if (loginUserResult.rtn !== 0) {
      throw new Error(`用户 PIN 登录失败，错误码: ${loginUserResult.errorCode}`);
    }

    // 从USBKey获取随机数，16Byte
    const usbKeyRandom = await generateRandom(deviceName, 16);
    if (usbKeyRandom.rtn !== 0) {
      throw new Error(`获取USBKey随机数失败，错误码: ${usbKeyRandom.errorCode}`);
    }

    // 生成角色随机数，4Byte
    const roleNameRandom = await generateRandom(deviceName, 4); // 4Byte
    if (roleNameRandom.rtn !== 0) {
      throw new Error(`获取角色随机数失败，错误码: ${roleNameRandom.errorCode}`);
    }

    // 获取容器名数组
    const containers = await enumCertContainer(deviceName);
    if (containers.rtn !== 0 || !containers.containerName) {
      throw new Error(`获取容器名失败，错误码: ${containers.errorCode}`);
    }

    // 获取第一个容器名
    const container = containers.containerName.split('||')[0];

    // 设置用户ID
    const setUserIDResult = await setUserID(deviceName, userId);
    if (setUserIDResult.rtn !== 0) {
      throw new Error(`设置用户ID失败，错误码: ${setUserIDResult.errorCode}`);
    }

    // 合并数据
    const combinedDataBytes = new Uint8Array([
      ...[0, 0, 0, 0],
      ...base64Decode(usbKeyRandom.outData),
      ...base64Decode(random),
    ]);

    const combinedDataBase64 = base64Encode(combinedDataBytes);

    const res = await setDigestMethod(deviceName, 1); // 1: SM3
    if (res.rtn !== 0) {
      throw new Error(`设置摘要算法失败，错误码: ${res.errorCode}`);
    }
    // 对数据做摘要(SM3)，32byte
    const digest = await digestData(deviceName, '', combinedDataBase64, 36); // 容器名为空，直接做SM3摘要
    if (digest.rtn !== 0) {
      throw new Error(`数据摘要失败，错误码: ${digest.errorCode}`);
    }

    // 设置用户ID
    const setUserIDResult1 = await setUserID(deviceName, userId);
    if (setUserIDResult1.rtn !== 0) {
      throw new Error(`设置用户ID失败，错误码: ${setUserIDResult.errorCode}`);
    }
    const res1 = await setDigestMethod(deviceName, 1); // 1: SM3
    if (res1.rtn !== 0) {
      throw new Error(`设置摘要算法失败，错误码: ${res.errorCode}`);
    }
    // 对摘要签名(SM2)，32byte
    const signature = await signData(
      deviceName,
      container,
      1, // keySpec: 1
      combinedDataBase64,
      36,
      1, // mode: 1 不预处理
    );
    if (signature.rtn !== 0) {
      throw new Error(`数据签名失败，错误码: ${signature.errorCode}`);
    }
    const publicKey = await exportPubKey(container, deviceName, 1, 3);
    if (publicKey.rtn !== 0) {
      throw new Error(`导出公钥失败，错误码: ${publicKey.errorCode}`);
    }
    // Logger('原数据:', combinedDataBase64);
    // Logger('公钥:', publicKey.pubKey);
    // Logger('签名:', signature.signed);
    // Logger('摘要:', digest.digest);

    const results: {
      digest: string;
      signature: string;
      originData: string;
    } = {
      digest: digest.digest,
      signature: signature.signed,
      originData: combinedDataBase64,
    };

    return results;
  } catch (error) {
    Logger('usbKey登录用户失败:', error);
    throw error;
  }
}

// 用户登录函数
export async function UsbLoginUser(random: string) {
  const roleName = 'superAdmin'; // 角色名称
  const authPassWd = '1234567812345678'; // 设备认证密钥
  const soPin = 'admin'; // 应用管理密码
  const userPin = '12345678'; // 用户密码
  const userId = '1234567812345678'; // 用户ID

  try {
    // 调用用户登录函数
    const results = await loginUser(roleName, authPassWd, soPin, userPin, userId, random);
    // Logger('登录成功，摘要和签名:', results);
    return results;
  } catch (error: any) {
    Logger(error.message);
    throw new Error(error?.message);
  }
}
